package com.iyunwen.datatool.dataload.impl;

import com.iyunwen.datatool.common.annotations.EventTypeAnnotation;
import com.iyunwen.datatool.common.enums.DataSourceTypeEnum;
import com.iyunwen.datatool.dataload.LogLoader;
import com.iyunwen.datatool.dataparse.DataParse;
import com.iyunwen.datatool.model.vo.BaseNormalizationDataVO;
import com.iyunwen.datatool.model.vo.SignalEventVO;
import com.iyunwen.datatool.utils.FileUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @description: 事件日志解析器
 * @author: Zhu.Guodong
 * @create: 2020-03-19 09:46
 * @version:
 */
@Slf4j
@Component
@EventTypeAnnotation(eventType = DataSourceTypeEnum.EVENT_LOG)
public class EventLogLoaderImpl implements LogLoader {
    /**
     * 表格行正则匹配表达式
     */
    private static String TR_REGEX = "<tr[^>]*>[\\s\\S]*?<\\/tr>";
    private static Pattern TR_PATTERN = Pattern.compile(TR_REGEX);

    /**
     * 表格背景色正则表达式
     */
    private static String BG_REGEX = "<tr.*?bgcolor=(?<objValue>.*?)\\s+.*?>";
    private static Pattern BG_PATTERN = Pattern.compile(BG_REGEX);

    /**
     * 表格列提取正则表达式
     */
    private static String TD_REGEX = "<td.*?>(?<objValue>.*?)</td>";
    private static Pattern TD_PATTERN = Pattern.compile(TD_REGEX);


    @Override
    public List<SignalEventVO> loadDataFromFile(File file) {
        long length = file.length();
        long sizeMB = length >> 20;
        String fileName = file.getName();
        if (!fileName.toLowerCase().endsWith("htm")) {
            //文件不支持
            log.warn("文件不支持，文件名:[{}]", fileName);
            return Collections.emptyList();
        }
        log.info("文件名:[{}],文件大小：{}MB ,开始解析....", fileName, sizeMB);

        long startTime = System.currentTimeMillis();
        List<SignalEventVO> signalEventVOList = readBigFile(file);
        log.info("文件名:[{}],数据量:{},解析耗时：{}ms", fileName, signalEventVOList.size(), System.currentTimeMillis() - startTime);

//        long startTime2 = System.currentTimeMillis();
//        List<SignalEventVO> readSmallFile = readSmallFile(file);
//        log.info("单字符耗时：{}", System.currentTimeMillis() - startTime2);

        return signalEventVOList;
    }

    @Override
    public List<BaseNormalizationDataVO> loadDataFromFile(File file, DataParse dataParse) {
        int readLength = 2 << 20;
        List<BaseNormalizationDataVO> baseNormalizationDataVOList = new ArrayList<>();
        BufferedReader reader = null;
        try {
            // 文件编码
            String fileCharsetName = FileUtils.getFileCharsetName(file);
            // 一次读一个字节
            InputStream inputStream = new FileInputStream(file);
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, fileCharsetName);

            reader = new BufferedReader(inputStreamReader, readLength);

            //读取数据缓存
            char[] charArray = new char[readLength];

            StringBuilder stringBuilder = new StringBuilder();
            int index = 0;
            while (-1 != reader.read(charArray)) {
                //读取的数据
                String temp = new String(charArray);
                //缓存清空
                charArray = new char[readLength];
                //和上一个tr标签合并
                stringBuilder.append(temp);
                String matchStr = stringBuilder.toString();
                //合并完清空缓存
                stringBuilder.delete(0, stringBuilder.length());


                Matcher m = TR_PATTERN.matcher(matchStr);
                //匹配截止位置
                int end = 0;
                while (m.find()) {
                    //正则匹配到的数据
                    String trItem = m.group();
                    //更新截止位置
                    end = m.end();
                    //解析数据
                    SignalEventVO signalEventVO = parseTrByRegex(trItem);
                    if (index > 0) {
                        //格式化数据
                        BaseNormalizationDataVO baseNormalizationDataVO = dataParse.formatItemData(signalEventVO);
                        baseNormalizationDataVOList.add(baseNormalizationDataVO);
                    }
                    index++;

                }

                //已经匹配到数据并且不是刚好以表格结尾符号结尾
                if (end > 0 && !matchStr.endsWith("</tr>")) {
                    String substring = matchStr.substring(end);
                    stringBuilder.append(substring);
                } else if (end == 0) {
                    //未匹配到数据，将本次匹配数据缓存用于下次的读取数据继续匹配
                    stringBuilder.append(matchStr);
                }

            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return baseNormalizationDataVOList;
    }

    /**
     * 单字符匹配
     *
     * @param file
     * @return
     */
    public List<SignalEventVO> readSmallFile(File file) {

        List<SignalEventVO> signalEventVOList = new ArrayList<>();
        BufferedReader reader = null;
        try {
            // 文件编码
            String fileCharsetName = FileUtils.getFileCharsetName(file);
            // 一次读一个字节
            InputStream inputStream = new FileInputStream(file);
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, fileCharsetName);
            reader = new BufferedReader(inputStreamReader, 2048);


            StringBuilder sb = new StringBuilder();
            int readItem;
            while (-1 != (readItem = reader.read())) {
                char readItemChar = (char) readItem;
                //判断html开始标签
                if ('<' == readItemChar) {
                    sb.append(readItemChar);
                } else if (sb.length() > 0) {
                    sb.append(readItemChar);
                }
                //是否是表格行标签，不是，废弃
                if (sb.length() > 2 && !sb.toString().startsWith("<tr")) {
                    sb.delete(0, sb.length());
                }

                //完整表格行判断
                if (sb.toString().startsWith("<tr") && sb.toString().endsWith("</tr>")) {
                    //System.out.println("------");

                    //解析表格中的数据
                    SignalEventVO signalEventVO = parseTrByRegex(sb.toString());
                    signalEventVOList.add(signalEventVO);

                    //清空表格行缓存变量
                    sb.delete(0, sb.length());
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return signalEventVOList;
    }


    /**
     * 读大文件
     *
     * @param file
     * @return
     */
    public List<SignalEventVO> readBigFile(File file) {
        int readLength = 2 << 20;
        List<SignalEventVO> signalEventVOList = new ArrayList<>();
        BufferedReader reader = null;
        try {
            // 文件编码
            String fileCharsetName = FileUtils.getFileCharsetName(file);
            // 一次读一个字节
            InputStream inputStream = new FileInputStream(file);
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, fileCharsetName);

            reader = new BufferedReader(inputStreamReader, readLength);

            //读取数据缓存
            char[] charArray = new char[readLength];

            StringBuilder stringBuilder = new StringBuilder();
            while (-1 != reader.read(charArray)) {
                //读取的数据
                String temp = new String(charArray);
                //缓存清空
                charArray = new char[readLength];
                //和上一个tr标签合并
                stringBuilder.append(temp);
                String matchStr = stringBuilder.toString();
                //合并完清空缓存
                stringBuilder.delete(0, stringBuilder.length());


                Matcher m = TR_PATTERN.matcher(matchStr);
                //匹配截止位置
                int end = 0;
                while (m.find()) {
                    //正则匹配到的数据
                    String trItem = m.group();
                    //更新截止位置
                    end = m.end();
                    //解析数据
                    SignalEventVO signalEventVO = parseTrByRegex(trItem);
                    signalEventVOList.add(signalEventVO);
                }

                //已经匹配到数据并且不是刚好以表格结尾符号结尾
                if (end > 0 && !matchStr.endsWith("</tr>")) {
                    String substring = matchStr.substring(end);
                    stringBuilder.append(substring);
                } else if (end == 0) {
                    //未匹配到数据，将本次匹配数据缓存用于下次的读取数据继续匹配
                    stringBuilder.append(matchStr);
                }

            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return signalEventVOList;
    }

    public SignalEventVO parseTrByRegex(String trString) {

        Matcher bgM = BG_PATTERN.matcher(trString);
        String bgcolor = "";
        if (bgM.find()) {
            bgcolor = bgM.group("objValue");
        }

        //行记录数据集合
        List<String> tdStrList = new ArrayList<>();

        Matcher m = TD_PATTERN.matcher(trString);
        while (m.find()) {
            tdStrList.add(m.group("objValue"));
        }

        SignalEventVO signalEventVO = new SignalEventVO();
        signalEventVO.setFieldValues(tdStrList);
        signalEventVO.setBgColour(bgcolor);

        return signalEventVO;
    }
}
